
#include "Chip.h"

__thread int* Chip::permutation = NULL;
__thread int Chip::traversalsNum = 0;
__thread int Chip::currContainer = 0;
__thread int Chip::currIter = 0;
//__thread int Chip::nextContainer = 0;
__thread bool Chip::originalPermutation = true;
__thread bool Chip::hasRandomSeed = false;

Chip::Chip(string containerType, int containersNum, int maxConsumers){
	this->containersNum = containersNum;
	this->containers = new TaskContainer*[containersNum];
	
	/* initialize the containers in the array. This part needs to be manually changed when adding a new type of container to the project */
	if(containerType.compare("containers.WorkStealingContainer") == 0)
	{
		for(int i = 0; i < containersNum; i++)
		{
			containers[i] = new WorkStealingContainer(maxConsumers);
		}
	}
	else if(containerType.compare("containers.ConcurrentListContainer") == 0)
	{
		for(int i = 0; i < containersNum; i++)
		{
			containers[i] = new ConcurrentListContainer();
		}
	}
	else
	{
		cout << containerType << " not supported" << endl;
		delete[] containers;
		exit(1);
	}
	/* generate initial permutation */
	this->initialPermutation = generatePermutation(); 
	permutation = initialPermutation;
}


// generate random permutation using Fisher-Yates shuffle algorithm
int* Chip::generatePermutation()   
{
	int* perm = new int[containersNum];
	for(int i = 0; i < containersNum; i++)
	{
		perm[i] = i;
	}
	if(!hasRandomSeed)
	{
		srand(TaskContainer::generateRandomSeed());
	}	
	// create permutation
	for(int i = containersNum-1; i > 0; i--)
	{
		int j = rand() % (i+1);
		int temp = perm[j];
		perm[j] = perm[i];
		perm[i] = temp;
	}
	return perm;
}


TaskContainer* Chip::getRandomContainer(){
	if(!hasRandomSeed)
	{
		srand(TaskContainer::generateRandomSeed());
		hasRandomSeed = true;
	}
	int curr = rand() % containersNum;
	currContainer = curr;
	currIter = curr;
	if(permutation == NULL)
	{
		permutation = generatePermutation();
	}
	return containers[permutation[curr]];		
}


TaskContainer* Chip::getNextContainer(){
	if((currIter+1) % containersNum != currContainer)
	{
		int curr = currIter;
		currIter++;
		return containers[permutation[curr % containersNum]];
	}
	else // completed a traversal
	{
		if(traversalsNum >= permutationRefreshRate)
		{
			if(originalPermutation)
			{
				originalPermutation = false;
			}
			else
			{
				delete[] permutation;
			}
			permutation = generatePermutation();
			traversalsNum = 0;
		}
		traversalsNum++;
		return NULL;
	}
}


void Chip::registerConsumer(int tid){
	for(int i = 0; i < containersNum; i++)
	{
		containers[i]->registerConsumer(tid);
	}
}


void Chip::registerProducer(int tid){
	for(int i = 0; i < containersNum; i++)
	{
		containers[i]->registerProducer(tid);
	}
}

/*
void setConsumersNum(int consumersNum){
	for(int i = 0; i < containersNum; i++)
	{
		containers[i]->setConsumersNum(consumersNum);
	}
}
*/


Chip::~Chip(){
	delete[] initialPermutation;
	for(int i = 0; i < containersNum; i++)
	{
		delete containers[i];
	}
	delete[] containers;
}

